#include "mainwindow.h"
#include "ui_mainwindow.h"

#include <QFileDialog>
#include <QFileInfo>
#include <QCloseEvent>
#include <QSettings>

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    // 创建间隔符
    actionSeparator = new QAction(this);
    actionSeparator->setSeparator(true);

    // 更新菜单
    updateMenus();
    connect(ui->mdiArea, SIGNAL(subWindowActivated(QMdiSubWindow*)), this, SLOT(updateMenus()));

    // 创建信号映射器
    windowMapper = new QSignalMapper(this);
    connect(windowMapper, SIGNAL(mappedObject(QObject*)), this, SLOT(setActiveSubWindow(QObject*)));
    // 更新窗口菜单
    updateWindowMenu();
    connect(ui->menuW, SIGNAL(aboutToShow()), this, SLOT(updateWindowMenu()));

    // 初始化窗口时读取窗口设置信息
    readSettings();

    // 初始化
    initWindow();
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::updateMenus()
{
    bool hasMdiChild = (activeMdiChild() != 0);
    ui->actionSave->setEnabled(hasMdiChild);
    ui->actionSaveAs->setEnabled(hasMdiChild);
    ui->actionPaste->setEnabled(hasMdiChild);
    ui->actionClose->setEnabled(hasMdiChild);
    ui->actionCloseAll->setEnabled(hasMdiChild);
    ui->actionTile->setEnabled(hasMdiChild);
    ui->actionCascade->setEnabled(hasMdiChild);
    ui->actionNext->setEnabled(hasMdiChild);
    ui->actionPrevious->setEnabled(hasMdiChild);

    actionSeparator->setVisible(hasMdiChild);

    // 有活动窗口且文本有被选择才能进行剪切和复制
    bool hasSelection = (activeMdiChild() && activeMdiChild()->textCursor().hasSelection());

    ui->actionCut->setEnabled(hasSelection);
    ui->actionCopy->setEnabled(hasSelection);

    // 有活动窗口且文本有撤销操作时撤销动作可用
    ui->actionUndo->setEnabled(activeMdiChild() && activeMdiChild()->document()->isUndoAvailable());
    // 有活动窗口且文本有恢复操作时恢复动作可用
    ui->actionRedo->setEnabled(activeMdiChild() && activeMdiChild()->document()->isRedoAvailable());
}

MdiChild *MainWindow::createMdiChild()
{
    // 创建MdiChild
    MdiChild *child = new MdiChild;
    ui->mdiArea->addSubWindow(child);

    connect(child, SIGNAL(copyAvailable(bool)), ui->actionCut, SLOT(setEnabled(bool)));
    connect(child, SIGNAL(copyAvailable(bool)), ui->actionCopy, SLOT(setEnabled(bool)));
    connect(child->document(), SIGNAL(undoAvailable(bool)), ui->actionCut, SLOT(setEnabled(bool)));
    connect(child->document(), SIGNAL(undoAvailable(bool)), ui->actionCut, SLOT(setEnabled(bool)));

    // 光标位置改变，重新显示行号和列号
    connect(child, SIGNAL(cursorPositionChanged()), this, SLOT(showTextRowAndCol()));

    return child;
}

void MainWindow::setActiveSubWindow(QObject *object)
{
    QMdiSubWindow *window = qobject_cast<QMdiSubWindow *>(object);
    // 设置为活动窗口
    if (!window)
        return;
    ui->mdiArea->setActiveSubWindow(qobject_cast<QMdiSubWindow *>(window));
}

void MainWindow::updateWindowMenu()
{
    // 清空窗口菜单
    ui->menuW->clear();
    ui->menuW->addAction(ui->actionClose);
    ui->menuW->addAction(ui->actionCloseAll);
    ui->menuW->addSeparator();
    ui->menuW->addAction(ui->actionTile);
    ui->menuW->addAction(ui->actionCascade);
    ui->menuW->addSeparator();
    ui->menuW->addAction(ui->actionNext);
    ui->menuW->addAction(ui->actionPrevious);
    ui->menuW->addAction(actionSeparator);

    // 如果有窗口则显示间隔器
    QList<QMdiSubWindow *> windows = ui->mdiArea->subWindowList();
    actionSeparator->setVisible(!windows.isEmpty());

    // 遍历查找文件名
    for(int i=0; i<windows.size(); ++i) {
        MdiChild *child = qobject_cast<MdiChild *>(windows.at(i)->widget());
        QString text;
        // 如果窗口小于9个，则设置快捷键
        if (i < 9)
            text = tr("&%1 %2").arg(i+1).arg(child->userFriendlyCurrentFile());
        else
            text = tr("%1 %2").arg(i+1).arg(child->userFriendlyCurrentFile());

        // 添加动作到窗口菜单
        QAction *action = ui->menuW->addAction(text);
        action->setCheckable(true);
        // 设置当前活动窗口动作为选择状态
        action->setChecked(child == activeMdiChild());

        // 触发map槽函数，发射mapped信号
        connect(action, SIGNAL(triggered(bool)), windowMapper, SLOT(map()));
        // 设置参数
        windowMapper->setMapping(action, windows.at(i));
    }
}

void MainWindow::writeSettings()
{
    // 写入窗口设置
    QSettings settings("yafeilinux", "myMdi");
    settings.setValue("pos", pos());
    settings.setValue("szie", size());
}

void MainWindow::showTextRowAndCol()
{
    // 状态栏显示行列号
    if (activeMdiChild()) {
        int rowNum = activeMdiChild()->textCursor().blockNumber() + 1;
        int colNum = activeMdiChild()->textCursor().columnNumber() + 1;

        ui->statusbar->showMessage(tr("%1行 : %2列").arg(rowNum).arg(colNum));
    }
}

void MainWindow::readSettings()
{
    // 读取窗口设置
    QSettings settings("yafeilinux", "myMdi");
    QPoint pos = settings.value("pos", QPoint(200, 200)).toPoint();
    QSize size = settings.value("size", QSize(400, 400)).toSize();
    move(pos);
    resize(size);
}

MdiChild *MainWindow::activeMdiChild()
{
    // 如果有活动窗口，则将其中心部件转换为MdiChild类型，没有则返回零
    if (QMdiSubWindow *activeSubWindow = ui->mdiArea->activeSubWindow())
        return qobject_cast<MdiChild *>(activeSubWindow->widget());
    return 0;
}

QMdiSubWindow *MainWindow::findMdiChild(const QString &filename)
{
    // 获取文件路径
    QString canonicalFilePath = QFileInfo(filename).canonicalFilePath();
    // 查找可能已经打开的过该文件的窗口
    foreach (QMdiSubWindow *window, ui->mdiArea->subWindowList()) {
        MdiChild *mdiChild = qobject_cast<MdiChild *>(window->widget());
        if (mdiChild->currentFile() == canonicalFilePath)
            return window;
    }

    return 0;
}

void MainWindow::initWindow()
{
    setWindowTitle("多文本编辑器");
    ui->mainToolBar->setWindowTitle("工具栏");
    // 当多文本区域内容超出可视区域后，出现滚动条
    ui->mdiArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
    ui->mdiArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);

    ui->statusbar->showMessage("欢迎使用多文本编辑器");
}

void MainWindow::closeEvent(QCloseEvent *event)
{
    // 先执行多文档区域的关闭操作
    ui->mdiArea->closeAllSubWindows();
    // 如果还有窗口没有关闭，则忽略该事件
    if (ui->mdiArea->currentSubWindow())
        event->ignore();
    else {
        // 写入窗口设置
        writeSettings();
        event->accept();
    }
}

void MainWindow::on_actionNew_triggered()
{
    // 创建Mdi
    MdiChild *child = createMdiChild();
    child->newFile();
    child->show();
}


void MainWindow::on_actionOpen_triggered()
{
    // 打开文件
    QString filename = QFileDialog::getOpenFileName(this);
    if (!filename.isEmpty()) {
        QMdiSubWindow *existing = findMdiChild(filename);
        // 判断文件是否已经打开
        if (existing) {
            ui->mdiArea->setActiveSubWindow(existing);
            return;
        }
        MdiChild *child = createMdiChild();
        if (child->loadFile(filename)) {
            ui->statusbar->showMessage("打开文件成功", 2000);
            child->show();
        } else {
            child->close();
        }
    }
}


void MainWindow::on_actionSave_triggered()
{
    // 保存文件
    if (activeMdiChild() && activeMdiChild()->save())
        ui->statusbar->showMessage("文件保存成功", 2000);
}


void MainWindow::on_actionUndo_triggered()
{
    // 撤销操作
    if (activeMdiChild())
        activeMdiChild()->undo();
}


void MainWindow::on_actionClose_triggered()
{
    // 关闭窗口
    ui->mdiArea->closeActiveSubWindow();
}


void MainWindow::on_actionSaveAs_triggered()
{
    // 另保存文件
    if (activeMdiChild() && activeMdiChild()->saveAs())
        ui->statusbar->showMessage("文件保存成功", 2000);
}


void MainWindow::on_actionExit_triggered()
{
    // 退出程序
    qApp->closeAllWindows();
}


void MainWindow::on_actionRedo_triggered()
{
    // 恢复操作
    if (activeMdiChild())
        activeMdiChild()->redo();
}


void MainWindow::on_actionCut_triggered()
{
    // 剪切操作
    activeMdiChild()->cut();
}


void MainWindow::on_actionCopy_triggered()
{
    // 复制操作
    activeMdiChild()->copy();
}


void MainWindow::on_actionPaste_triggered()
{
    // 粘贴操作
    activeMdiChild()->paste();
}

